package com.ccp.dev.system.license;


import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.encrypt.EncryptUtil;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.system.service.SysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.util.ClassUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * license验证类
 */
public class SysLicense {

    private static String fileName = "license.lic";

    private static String encoding = "UTF-8";

    private static Logger logger = LoggerFactory.getLogger(SysLicense.class);

    protected static int sessionCount = 0;

    protected static int licType = 3;


    /**
     * 获取 license 串 ;
     * @return license串
     */
    private static String getLicenseStr() {
        //2019-11-15 jyq修改
        String licenseTxt = null;
        InputStream inputStream = ClassUtils.getDefaultClassLoader().getResourceAsStream(fileName);
        try {
            if (null!=inputStream) {
                InputStreamReader read = new InputStreamReader(inputStream, encoding);
                BufferedReader bufferedReader = new BufferedReader(read);
                String licenseTxtRed = null;
                while ((licenseTxtRed = bufferedReader.readLine()) != null) {
                    licenseTxt = licenseTxtRed;
                }

                read.close();

                logger.info("读取文件成功！");
            } else {
                logger.error("找不到指定文件！");
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return licenseTxt;
    }

    /**
     * 验证 license
     *
     * @return true 验证通过 false 验证失败
     * @throws Exception 抛出异常
     */
    public static Boolean validateLicnese() throws Exception {
        Boolean validate;
        String licenseStr = getLicenseStr();
        String sessionNum = getSessionCount(licenseStr);
        String licenseType = getLicenseType(licenseStr);
        if (licenseType != null && isNumeric(licenseType)) {
            licType = Integer.parseInt(licenseType);
        } else {
            logger.error("请检查license.lic文件！");
        }

        if (sessionNum != null && isNumeric(sessionNum)) {
            sessionCount = Integer.parseInt(sessionNum);
        } else {
            logger.error("请检查license.lic文件！");
        }

        if (licType == 1 || licType == 3) {
            validate = validateLicenseValidTill(licenseStr);
        } else if (licType == 4 || licType == 5) {
            validate = validateLicenseCustomer(licenseStr);
        } else if (licType == 6) {
            validate = validateLicenseIPAddress(licenseStr);
        } else {
            validate = true;
        }

        return validate;
    }


    /**
     * 根据时间期间验证 license
     *
     * @param licenseStr license串
     * @return true 验证通过  false 验证失败
     * @throws Exception 抛出异常
     */
    private static Boolean validateLicenseValidTill(String licenseStr) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        if (licenseStr != null) {
            String licStr = decryptLicenseStr(licenseStr);

            Date startDate = format.parse(licStr.split("_")[1]);
            Date endDate = format.parse(licStr.split("_")[2]);
            Date nowDate = new Date();
            if (startDate.getTime() <= nowDate.getTime() && endDate.getTime() >= nowDate.getTime()) {
                return true;
            }

        } else {
            logger.error("请检查license.lic文件！");
        }
        return false;

    }

    /**
     * 根据cpu硬件码 验证 license
     *
     * @param licenseStr license串
     * @return true 验证通过 false 验证失败
     */
    private static Boolean validateLicenseCustomer(String licenseStr) throws Exception {
        String customerCpuNumber = "";
        if (licenseStr != null) {
            String licStr = decryptLicenseStr(licenseStr);

            String[] lic = licStr.split("_");

            if (lic != null && lic.length > 4) {
                if (lic[4] != null) {
                    customerCpuNumber = lic[4];
                    if (getCustomerCpuNumber().equals(customerCpuNumber)) {
                        return true;
                    } else {
                        logger.error("失效的license！");
                        return false;
                    }
                } else {
                    logger.error("请检查license.lic文件！");
                    return false;
                }

            } else {
                logger.error("请检查license.lic文件！");
                return false;
            }

        } else {
            logger.error("请检查license.lic文件！");
        }

        return false;
    }

    /**
     * 验证license中的IP地址
     *
     * @param licenseStr license串
     * @return true 验证通过 false 验证失败
     * @throws Exception 抛出异常
     */
    private static Boolean validateLicenseIPAddress(String licenseStr) throws Exception {
        boolean isValid = false;
        String ipAddress = "";
        if (licenseStr != null) {
            String[] lic = decryptLicenseStr(licenseStr).split("_");
            if (lic != null && lic.length > 5) {
                if (!"".equals(lic[5])) {
                    ipAddress = lic[5];
                    if (getCustomerIpAddress().contains(ipAddress)) {
                        isValid = true;
                    } else {
                        logger.error("失效的license！");
                    }
                } else {
                    logger.error("请检查license.lic文件！");
                }
            } else {
                logger.error("请检查license.lic文件！");
            }
        } else {
            logger.error("请检查license.lic文件！");
        }
        return isValid;
    }

    /**
     * 获取本机ip地址
     * @return ipList
     */
    public static List<String> getCustomerIpAddress() {
        List<String> retList = new ArrayList<>();
        try {
            List<NetworkInterface> netlist = new ArrayList<NetworkInterface>();
            //获取当前环境下的所有网卡
            Enumeration<?> netInterfaces = NetworkInterface.getNetworkInterfaces();
            while (netInterfaces.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement();
                //过滤 lo网卡
                if (ni.isLoopback()) {
                    continue;
                }
                //倒置网卡顺序
                netlist.add(0, ni);
            }  /*
                  用上述方法获取所有网卡时，得到的顺序与服务器中用ifconfig命令看到的网卡顺序相反，
                  因此，想要从第一块网卡开始遍历时，需要将Enumeration<?>中的元素倒序 */
            //遍历每个网卡
            for (NetworkInterface list : netlist) {
                //获取网卡下所有ip
                Enumeration<?> cardipaddress = list.getInetAddresses();
                //将网卡下所有ip地址取出
                while (cardipaddress.hasMoreElements()) {
                    InetAddress ip = (InetAddress) cardipaddress.nextElement();
                    if (!ip.isLoopbackAddress()) {
                        if ("127.0.0.1".equalsIgnoreCase(ip.getHostAddress())) {
                            continue;
                        }
                        //过滤ipv6地址
                        if (ip instanceof Inet6Address) {
                            continue;
                        }
                        //返回ipv4地址
                        if (ip instanceof Inet4Address) {
                            retList.add(ip.getHostAddress());
                        }
                    }
                }
            }
            if (retList.isEmpty()) {
                retList.add(InetAddress.getLocalHost().getHostAddress());
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return retList;
    }

    private static String decryptLicenseStr(String licenseStr) throws Exception {
        return EncryptUtil.decrypt(licenseStr);
    }

    private static String getSessionCount(String licenseStr) throws Exception {

        if (licenseStr != null) {
            String licStr = decryptLicenseStr(licenseStr);

            String[] lic = licStr.split("_");

            if (lic != null && lic.length > 3) {

                return lic[3];

            } else {
                return null;
            }

        } else {
            logger.error("请检查license.lic文件！");
        }
        return null;

    }

    /**
     * 获取 license 类型
     *
     * @param licenseStr license串
     * @return license类型
     * @throws Exception 抛出异常
     */
    private static String getLicenseType(String licenseStr) throws Exception {

        if (licenseStr != null) {
            String licStr = decryptLicenseStr(licenseStr);

            String[] lic = licStr.split("_");

            if (lic != null && lic.length > 0) {

                return lic[0];

            } else {
                return null;
            }

        } else {
            logger.error("请检查license.lic文件！");
        }
        return null;

    }

    /**
     * 判断是否是数字
     *
     * @param str 字符串
     * @return true  是   false 否
     */
    private static boolean isNumeric(String str) {
        String patternStr = "^\\d+$";
        Pattern pattern = Pattern.compile(patternStr);
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    /**
     * 根据session验证license
     *
     * @param request HttpServletRequest
     * @return true 验证通过 false 验证失败
     */
    public static boolean validateSessionLicnese(HttpServletRequest request) {
        if (licType == 2 || licType == 3 || licType == 5) {
            int signNum = setSessionLicense(request);
            if (signNum == 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取电脑cpu码
     *
     * @return cpu码
     */
    private static String getCustomerCpuNumber() {
        try {

            Process process = Runtime.getRuntime().exec(new String[]{"wmic", "cpu", "get", "ProcessorId"});
            process.getOutputStream().close();
            Scanner scanner = new Scanner(process.getInputStream());
            String property = scanner.next();
            String serial = scanner.next();
            return serial;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 重新获取当前用户数并setsessionLicense
     *
     * @param request HttpServletRequest
     * @return 0 用户过多，1正常登陆
     */
    private static int setSessionLicense(HttpServletRequest request) {
        SysUserService sysUserService = AppUtil.getBean(SysUserService.class);
        List<SysUser> list = sysUserService.getOnLineUsers();
        if (!list.isEmpty()) {
            if (list.size() >= sessionCount) {
                //维护在线用户
                SessionRegistry sessionRegistry = AppUtil.getBean(SessionRegistry.class);
                sessionRegistry.removeSessionInformation(request.getSession().getId());
                return 0;
            } else {
                return 1;
            }
        } else {
            return 1;
        }
    }
}
